﻿Imports Microsoft.Build.Framework
Imports Microsoft.Build.Utilities
Imports Microsoft.CSharp
Imports Microsoft.VisualBasic
Imports Microsoft.Win32
Imports System
Imports System.CodeDom
Imports System.CodeDom.Compiler
Imports System.Collections
Imports System.Collections.Specialized
Imports System.Diagnostics
Imports System.Globalization
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Workflow.ComponentModel.Design
Imports System.Workflow.ComponentModel.Serialization

Namespace System.Workflow.ComponentModel.Compiler
    Public NotInheritable Class CompileWorkflowTask
        Inherits Task
        Implements ITask
        ' Methods
        Public Sub New()
            MyBase.New(New ResourceManager("System.Workflow.ComponentModel.BuildTasksStrings", Assembly.GetExecutingAssembly))
            Me.temporaryFiles = New StringCollection
        End Sub

        Public Overrides Function Execute() As Boolean
            If Not Me.ValidateParameters Then
                Return False
            End If
            If (Me.WorkflowMarkupFiles Is Nothing) Then
                MyBase.Log.LogMessageFromResources(MessageImportance.Normal, "NoXomlFiles", New Object(0  - 1) {})
            End If
            If ((Me.ReferenceFiles Is Nothing) OrElse (Me.ReferenceFiles.Length = 0)) Then
                MyBase.Log.LogMessageFromResources(MessageImportance.Normal, "NoReferenceFiles", New Object(0  - 1) {})
            End If
            If ((Me.SourceCodeFiles Is Nothing) OrElse (Me.SourceCodeFiles.Length = 0)) Then
                MyBase.Log.LogMessageFromResources(MessageImportance.Normal, "NoSourceCodeFiles", New Object(0  - 1) {})
            End If
            If (((Me.HostObject Is Nothing) OrElse (TypeOf Me.HostObject Is IWorkflowBuildHostProperties AndAlso DirectCast(Me.HostObject, IWorkflowBuildHostProperties).SkipWorkflowCompilation)) AndAlso (String.Compare(Process.GetCurrentProcess.ProcessName, "devenv", StringComparison.OrdinalIgnoreCase) = 0)) Then
                Return True
            End If
            Dim num As Integer = 0
            Dim num2 As Integer = 0
            Dim parameters As New WorkflowCompilerParameters
            Dim logger As IWorkflowCompilerErrorLogger = Nothing
            Dim provider As IServiceProvider = Nothing
            If TypeOf Me.HostObject Is IOleServiceProvider Then
                provider = New ServiceProvider([TryCast](Me.HostObject,IOleServiceProvider))
                logger = [TryCast](provider.GetService(GetType(IWorkflowCompilerErrorLogger)),IWorkflowCompilerErrorLogger)
            End If
            Dim strArray As String() = CompileWorkflowTask.GetFiles(Me.SourceCodeFiles, Me.ProjectDirectory)
            Dim item As ITaskItem
            For Each item In Me.ReferenceFiles
                If Not StandardWorkflowAssemblies.Contains(item.ItemSpec) Then
                    parameters.ReferencedAssemblies.Add(item.ItemSpec)
                End If
            Next
            parameters.CompilerOptions = Me.PrepareCompilerOptions
            parameters.GenerateCodeCompileUnitOnly = True
            parameters.LanguageToUse = Me.ProjectType.ToString
            parameters.TempFiles.KeepFiles = Me.ShouldKeepTempFiles
            parameters.OutputAssembly = Me.AssemblyName
            If Not String.IsNullOrEmpty(Me.assemblyName) Then
                Dim str As String = If(parameters.GenerateExecutable, ".exe", ".dll")
                parameters.OutputAssembly = (parameters.OutputAssembly & str)
            End If
            Dim provider2 As CodeDomProvider = Nothing
            If (Me.ProjectType = SupportedLanguages.VB) Then
                provider2 = CompilerHelpers.CreateCodeProviderInstance(GetType(VBCodeProvider))
            Else
                provider2 = CompilerHelpers.CreateCodeProviderInstance(GetType(CSharpCodeProvider))
            End If
            [Using] files As TempFileCollection = New TempFileCollection(Environment.GetEnvironmentVariable("temp", EnvironmentVariableTarget.User), True)
                Dim strArray2 As String()
                Me.outputFiles = New TaskItem(1  - 1) {}
                If (Not Me.WorkflowMarkupFiles Is Nothing) Then
                    strArray2 = New String((Me.WorkflowMarkupFiles.GetLength(0) + strArray.Length)  - 1) {}
                    Dim index As Integer = 0
                    Do While (index < Me.WorkflowMarkupFiles.GetLength(0))
                        strArray2(index) = Path.Combine(Me.ProjectDirectory, Me.WorkflowMarkupFiles(index).ItemSpec)
                        index += 1
                    Loop
                    strArray.CopyTo(strArray2, index)
                Else
                    strArray2 = New String(strArray.Length  - 1) {}
                    strArray.CopyTo(strArray2, 0)
                End If
                Dim results As WorkflowCompilerResults = New WorkflowCompiler().Compile(parameters, strArray2)
                Dim error As WorkflowCompilerError
                For Each error In results.Errors
                    If [error].IsWarning Then
                        num2 += 1
                        If (Not logger Is Nothing) Then
                            [error].FileName = Path.Combine(Me.ProjectDirectory, [error].FileName)
                            logger.LogError([error])
                            logger.LogMessage(([error].ToString & ChrW(10)))
                        Else
                            MyBase.Log.LogWarning([error].ErrorText, New Object() { [error].ErrorNumber, [error].FileName, [error].Line, [error].Column })
                        End If
                    Else
                        num += 1
                        If (Not logger Is Nothing) Then
                            [error].FileName = Path.Combine(Me.ProjectDirectory, [error].FileName)
                            logger.LogError([error])
                            logger.LogMessage(([error].ToString & ChrW(10)))
                        Else
                            MyBase.Log.LogError([error].ErrorText, New Object() { [error].ErrorNumber, [error].FileName, [error].Line, [error].Column })
                        End If
                    End If
                Next
                If Not results.Errors.HasErrors Then
                    Dim compiledUnit As CodeCompileUnit = results.CompiledUnit
                    If (Not compiledUnit Is Nothing) Then
                        Dim workflowCompilerOptions As IWorkflowCompilerOptionsService = Nothing
                        If (Not provider Is Nothing) Then
                            workflowCompilerOptions = [TryCast](provider.GetService(GetType(IWorkflowCompilerOptionsService)),IWorkflowCompilerOptionsService)
                        End If
                        If (workflowCompilerOptions Is Nothing) Then
                            workflowCompilerOptions = New WorkflowCompilerOptionsService(parameters)
                        End If
                        WorkflowMarkupSerializationHelpers.FixStandardNamespacesAndRootNamespace(compiledUnit.Namespaces, workflowCompilerOptions.RootNamespace, CompilerHelpers.GetSupportedLanguage(workflowCompilerOptions))
                        Dim path As String = files.AddExtension(provider2.FileExtension)
                        [Using] writer As StreamWriter = New StreamWriter(New FileStream(path, FileMode.Create, FileAccess.Write), Encoding.UTF8)
                            Dim options As New CodeGeneratorOptions { _
                                .BracingStyle = "C" _
                            }
                            provider2.GenerateCodeFromCompileUnit(compiledUnit, writer, options)
                        End [Using]
                        Me.outputFiles(0) = New TaskItem(path)
                        Me.temporaryFiles.Add(path)
                        MyBase.Log.LogMessageFromResources(MessageImportance.Normal, "TempCodeFile", New Object() { path })
                    End If
                End If
            End [Using]
            If (((num > 0) OrElse (num2 > 0)) AndAlso (Not logger Is Nothing)) Then
                logger.LogMessage(String.Format(CultureInfo.CurrentCulture, ChrW(10) & "Compile complete -- {0} errors, {1} warnings " & ChrW(10), New Object() { num, num2 }))
            End If
            MyBase.Log.LogMessageFromResources(MessageImportance.Normal, "XomlValidationCompleted", New Object() { num, num2 })
            Return (num = 0)
        End Function

        Private Shared Function GetFiles(ByVal taskItems As ITaskItem(), ByVal projDir As String) As String()
            If (taskItems Is Nothing) Then
                Return New String(0  - 1) {}
            End If
            Dim strArray As String() = New String(taskItems.Length  - 1) {}
            Dim i As Integer
            For i = 0 To taskItems.Length - 1
                If (Not projDir Is Nothing) Then
                    strArray(i) = Path.Combine(projDir, taskItems(i).ItemSpec)
                Else
                    strArray(i) = taskItems(i).ItemSpec
                End If
            Next i
            Return strArray
        End Function

        Private Shared Function HasManifestResourceName(ByVal resourceFile As ITaskItem, <Out> ByRef manifestResourceName As String) As Boolean
            Dim enumerator As IEnumerator = resourceFile.MetadataNames.GetEnumerator
            manifestResourceName = Nothing
            Dim flag As Boolean = False
            Do While (Not flag AndAlso enumerator.MoveNext)
                Dim current As String = CStr(enumerator.Current)
                If (current = "ManifestResourceName") Then
                    flag = True
                    manifestResourceName = resourceFile.GetMetadata(current)
                End If
            Loop
            Return flag
        End Function

        Private Function PrepareCompilerOptions() As String
            Dim builder As New StringBuilder
            If Me.DelaySign Then
                builder.Append(" /delaysign+")
            End If
            If ((Not Me.KeyContainer Is Nothing) AndAlso (Me.KeyContainer.Trim.Length > 0)) Then
                builder.AppendFormat(" /keycontainer:{0}", Me.KeyContainer)
            End If
            If ((Not Me.KeyFile Is Nothing) AndAlso (Me.KeyFile.Trim.Length > 0)) Then
                builder.AppendFormat(" /keyfile:""{0}""", Path.Combine(Me.ProjectDirectory, Me.KeyFile))
            End If
            If ((Not Me.compilationOptions Is Nothing) AndAlso (Me.compilationOptions.Length > 0)) Then
                Dim item As ITaskItem
                For Each item In Me.compilationOptions
                    Dim metadata As String = item.GetMetadata("value")
                    Dim str2 As String = item.GetMetadata("delimiter")
                    If String.IsNullOrEmpty(metadata) Then
                        builder.AppendFormat(" /{0}", item.ItemSpec)
                    ElseIf String.IsNullOrEmpty(str2) Then
                        builder.AppendFormat(" /{0}{1}", item.ItemSpec, metadata)
                    Else
                        builder.AppendFormat(" /{0}{1}{2}", item.ItemSpec, str2, metadata)
                    End If
                Next
            End If
            If ((Not Me.resourceFiles Is Nothing) AndAlso (Me.resourceFiles.Length > 0)) Then
                Dim item2 As ITaskItem
                For Each item2 In Me.resourceFiles
                    Dim str3 As String
                    If CompileWorkflowTask.HasManifestResourceName(item2, str3) Then
                        builder.AppendFormat(" /resource:""{0}"",""{1}""", Path.Combine(Me.ProjectDirectory, item2.ItemSpec), str3)
                    Else
                        builder.AppendFormat(" /resource:""{0}""", Path.Combine(Me.ProjectDirectory, item2.ItemSpec))
                    End If
                Next
            End If
            If (Me.ProjectType = SupportedLanguages.VB) Then
                If Not String.IsNullOrEmpty(Me.RootNamespace) Then
                    builder.AppendFormat(" /rootnamespace:{0}", Me.RootNamespace)
                End If
                builder.AppendFormat(" /imports:{0}", Me.Imports.Replace(";"c, ","c))
            End If
            Return builder.ToString
        End Function

        Private Function ShouldKeepTempFiles() As Boolean
            Dim flag As Boolean = False
            If (Me.ProjectType = SupportedLanguages.VB) Then
                Return True
            End If
            Try 
                Dim key As RegistryKey = Registry.LocalMachine.OpenSubKey(Helpers.ProductRootRegKey)
                If (Not key Is Nothing) Then
                    flag = (Convert.ToInt32(key.GetValue("KeepTempFiles"), CultureInfo.InvariantCulture) <> 0)
                End If
            Catch obj1 As Object
            End Try
            Return flag
        End Function

        Private Function ValidateParameters() As Boolean
            If ((Me.ProjectDirectory Is Nothing) OrElse (Me.ProjectDirectory.Trim.Length = 0)) Then
                MyBase.Log.LogErrorFromResources("NoProjectType", New Object(0  - 1) {})
                Return False
            End If
            If ((Me.ProjectExtension Is Nothing) OrElse (Me.ProjectExtension.Trim.Length = 0)) Then
                MyBase.Log.LogErrorFromResources("NoProjectType", New Object(0  - 1) {})
                Return False
            End If
            If ((String.Compare(Me.ProjectExtension, ".csproj", StringComparison.OrdinalIgnoreCase) <> 0) AndAlso (String.Compare(Me.ProjectExtension, ".vbproj", StringComparison.OrdinalIgnoreCase) <> 0)) Then
                MyBase.Log.LogErrorFromResources("UnsupportedProjectType", New Object(0  - 1) {})
                Return False
            End If
            Return True
        End Function


        ' Properties
        Public Property AssemblyName As String
            Get
                Return Me.assemblyName
            End Get
            Set(ByVal value As String)
                Me.assemblyName = value
            End Set
        End Property

        Public Property CompilationOptions As ITaskItem()
            Get
                Return Me.compilationOptions
            End Get
            Set(ByVal value As ITaskItem())
                Me.compilationOptions = value
            End Set
        End Property

        Public Property DelaySign As Boolean
            Get
                Return Me.delaySign
            End Get
            Set(ByVal value As Boolean)
                Me.delaySign = value
            End Set
        End Property

        Public ReadOnly Property HostObject As Object
            Get
                Return Me.hostObject
            End Get
        End Property

        Public Property [Imports] As String
            Get
                Return Me.imports
            End Get
            Set(ByVal value As String)
                Me.imports = value
            End Set
        End Property

        <Output> _
        Public ReadOnly Property KeepTemporaryFiles As String
            Get
                Return Me.ShouldKeepTempFiles.ToString
            End Get
        End Property

        Public Property KeyContainer As String
            Get
                Return Me.keyContainer
            End Get
            Set(ByVal value As String)
                Me.keyContainer = value
            End Set
        End Property

        Public Property KeyFile As String
            Get
                Return Me.keyFile
            End Get
            Set(ByVal value As String)
                Me.keyFile = value
            End Set
        End Property

        Private Property Microsoft.Build.Framework.ITask.HostObject As ITaskHost
            Get
                Return DirectCast(Me.hostObject, ITaskHost)
            End Get
            Set(ByVal value As ITaskHost)
                Me.hostObject = value
            End Set
        End Property

        <Output> _
        Public ReadOnly Property OutputFiles As ITaskItem()
            Get
                If (Me.outputFiles Is Nothing) Then
                    If (Me.ProjectType = SupportedLanguages.VB) Then
                        Me.outputFiles = New ITaskItem(0  - 1) {}
                    Else
                        Dim list As New ArrayList
                        If (Not Me.WorkflowMarkupFiles Is Nothing) Then
                            list.AddRange(Me.WorkflowMarkupFiles)
                        End If
                        Me.outputFiles = [TryCast](list.ToArray(GetType(ITaskItem)),ITaskItem())
                    End If
                End If
                Return Me.outputFiles
            End Get
        End Property

        Public Property ProjectDirectory As String
            Get
                Return Me.projectDirectory
            End Get
            Set(ByVal value As String)
                Me.projectDirectory = value
            End Set
        End Property

        Public Property ProjectExtension As String
            Get
                Return Me.projectExt
            End Get
            Set(ByVal value As String)
                Me.projectExt = value
                If (String.Compare(Me.projectExt, ".csproj", StringComparison.OrdinalIgnoreCase) = 0) Then
                    Me.ProjectType = SupportedLanguages.CSharp
                ElseIf (String.Compare(Me.projectExt, ".vbproj", StringComparison.OrdinalIgnoreCase) = 0) Then
                    Me.ProjectType = SupportedLanguages.VB
                End If
            End Set
        End Property

        Private Property ProjectType As SupportedLanguages
            Get
                Return Me.projectType
            End Get
            Set(ByVal value As SupportedLanguages)
                Me.projectType = value
            End Set
        End Property

        Public Property ReferenceFiles As ITaskItem()
            Get
                Return Me.referenceFiles
            End Get
            Set(ByVal value As ITaskItem())
                Me.referenceFiles = value
            End Set
        End Property

        Public Property ResourceFiles As ITaskItem()
            Get
                Return Me.resourceFiles
            End Get
            Set(ByVal value As ITaskItem())
                Me.resourceFiles = value
            End Set
        End Property

        Public Property RootNamespace As String
            Get
                Return Me.rootNamespace
            End Get
            Set(ByVal value As String)
                Me.rootNamespace = value
            End Set
        End Property

        Public Property SourceCodeFiles As ITaskItem()
            Get
                Return Me.sourceCodeFiles
            End Get
            Set(ByVal value As ITaskItem())
                Me.sourceCodeFiles = value
            End Set
        End Property

        <Output> _
        Public ReadOnly Property TemporaryFiles As String()
            Get
                Dim array As String() = New String(Me.temporaryFiles.Count  - 1) {}
                Me.temporaryFiles.CopyTo(array, 0)
                Return array
            End Get
        End Property

        Public Property WorkflowMarkupFiles As ITaskItem()
            Get
                Return Me.xomlFiles
            End Get
            Set(ByVal value As ITaskItem())
                If (Not value Is Nothing) Then
                    Dim list As New ArrayList
                    Dim item As ITaskItem
                    For Each item In value
                        If (Not item Is Nothing) Then
                            Dim itemSpec As String = item.ItemSpec
                            If ((Not itemSpec Is Nothing) AndAlso itemSpec.EndsWith(".xoml", StringComparison.OrdinalIgnoreCase)) Then
                                list.Add(item)
                            End If
                        End If
                    Next
                    If (list.Count > 0) Then
                        Me.xomlFiles = [TryCast](list.ToArray(GetType(ITaskItem)),ITaskItem())
                    End If
                Else
                    Me.xomlFiles = value
                End If
            End Set
        End Property


        ' Fields
        Private assemblyName As String
        Private compilationOptions As ITaskItem()
        Private delaySign As Boolean
        Private hostObject As Object
        Private [imports] As String
        Private keyContainer As String
        Private keyFile As String
        Private outputFiles As ITaskItem()
        Private projectDirectory As String
        Private projectExt As String
        Private projectType As SupportedLanguages
        Private referenceFiles As ITaskItem()
        Private resourceFiles As ITaskItem()
        Private rootNamespace As String
        Private sourceCodeFiles As ITaskItem()
        Private temporaryFiles As StringCollection
        Private xomlFiles As ITaskItem()
    End Class
End Namespace

